#import "wooddoc.h"
#import "ooe_server.h"

static NXAtom WoodPboardType;
static NXAtom WoodStylePboardType;
static NXAtom WoodOOEApplicationInfoPboardType;
static NXAtom WoodName;

@implementation WoodDoc (PasteBoard)

+ initializePasteboardTypes
{
	WoodPboardType = NXUniqueString("Wood Pasteboard Type");
	WoodStylePboardType = NXUniqueString("Wood Style Pasteboard Type");
	WoodOOEApplicationInfoPboardType = NXUniqueString(OOE_APPINFO_PASTEBOARDTYPE);
	WoodName = NXUniqueString("Wood.app");
	return self;
}

- copyToPasteboard:pboard
{
	NXStream *stream;
	NXTypedStream *ts;
	char *dataptr;
	int length,maxlen;
	NXAtom typelist[4];
	BOOL error = YES;

	if(!lastSelectedNode)
		return nil;
	typelist[0] = WoodPboardType;
	typelist[1] = NXPostScriptPboardType;
	typelist[2] = NXAsciiPboardType;
	typelist[3] = WoodOOEApplicationInfoPboardType;
	stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	if(stream){
		ts = NXOpenTypedStream(stream, NX_WRITEONLY);
	   	if(ts){
			[lastSelectedNode writeToPBStream:ts];
			NXCloseTypedStream(ts);
			NXGetMemoryBuffer(stream, &dataptr, &length, &maxlen);
			[pboard declareTypes:typelist  num:4  owner:[self class]];
			[pboard writeType:WoodPboardType  data:dataptr  length:length];
			error = NO;
	   	}
	   	NXCloseMemory(stream, NX_FREEBUFFER);
	}
	return (error ? nil : self);
}

- pasteFromPasteboard:pboard
{
	BOOL error = YES;
	id pasteTree = nil;
   	char *dataptr;
   	int length;
   	NXTypedStream *ts;
   	NXStream *stream;

   	if(includesType([pboard types], WoodPboardType)){
		[pboard readType:WoodPboardType data:&dataptr length:&length];
		stream = NXOpenMemory(dataptr, length, NX_READONLY);
		if(stream){
			ts = NXOpenTypedStream(stream, NX_READONLY);
			if(ts){
				pasteTree = NXReadObject(ts);
				[self makeAddTree:pasteTree];
				NXCloseTypedStream(ts);
			}
		}
	}
	return (error ? nil : self);
}

- copyStyleToPasteboard:pboard
{
	NXStream *stream;
	NXTypedStream *ts;
	char *dataptr;
	int length,maxlen;
	NXAtom typelist[1];
	BOOL error = YES;
	
	if(!lastSelectedNode)
		return nil;
	typelist[0] = WoodStylePboardType;
	stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	if(stream){
		ts = NXOpenTypedStream(stream, NX_WRITEONLY);
	   	if(ts){
			[lastSelectedNode writeStyleToPBStream:ts];
			NXCloseTypedStream(ts);
			NXGetMemoryBuffer(stream, &dataptr, &length, &maxlen);
			[pboard declareTypes:typelist  num:1  owner:[self class]];
			[pboard writeType:WoodStylePboardType  data:dataptr  length:length];
			error = NO;
	   	}
	   	NXCloseMemory(stream, NX_FREEBUFFER);
	}
	return (error ? nil : self);
}

- pasteStyleFromPasteboard:pboard
{
	BOOL error = YES;
   	char *dataptr;
   	int length;
   	NXTypedStream *ts;
   	NXStream *stream;
	
	if(!lastSelectedNode)
		return nil;
	if(includesType([pboard types], WoodStylePboardType)){
		[pboard readType:WoodStylePboardType data:&dataptr length:&length];
		stream = NXOpenMemory(dataptr, length, NX_READONLY);
		if(stream){
			ts = NXOpenTypedStream(stream, NX_READONLY);
			if(ts){
				[lastSelectedNode readStyleFromPBStream:ts];
				[[NXApp inspectorManager] revert:self];
				NXCloseTypedStream(ts);
			}
		}
	}
	return (error ? nil : self);
}

+ convert:(NXTypedStream *)ts to:(const char *)type using:(SEL)writer toPasteboard:(Pasteboard *)pb
{
    Window *w;
	Tree *pbtree;
    NXZone *zone;
    NXStream *stream;
    TreeView *scrapper;
    NXRect scrapperFrame = {{0.0, 0.0}, {11.0*72.0, 14.0*72.0}};

    if(!ts) 
		return self;
    zone = NXCreateZone(vm_page_size, vm_page_size, NO);
    NXNameZone(zone, "Scrapper");
    scrapper = [[TreeView allocFromZone:zone] initFrame:&scrapperFrame];
    NXSetTypedStreamZone(ts, zone);
    pbtree = NXReadObject(ts);
	[scrapper checkResize:NULL for:pbtree];
	[scrapper getFrame:&scrapperFrame];
    w = [[Window allocFromZone:zone] initContent:&scrapperFrame
					   style:NX_PLAINSTYLE
					 backing:NX_NONRETAINED
				      buttonMask:0
					   defer:NO];
    [w reenableDisplay];
    [w setContentView:scrapper];
    stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
    [scrapper perform:writer with:(id)stream with:pbtree];
	NXSeek(stream, 0, NX_FROMSTART);
    [pb writeType:type fromStream:stream];
    NXCloseMemory(stream, NX_FREEBUFFER);
    [pbtree free];
    [w free];
    NXDestroyZone(zone);
    return self;
}

+ convert:(NXTypedStream *)ts toAsciiPasteboard:(Pasteboard *)pb
{
	Tree *pbtree;
    NXStream *stream;
	
	pbtree = NXReadObject(ts);
	stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	[pbtree writeToMMAPB:stream];
	NXSeek(stream, 0, NX_FROMSTART);
	[pb writeType:NXAsciiPboardType fromStream:stream];
    NXCloseMemory(stream, NX_FREEBUFFER);
    [pbtree free];
	return self;
}

+ pasteboard:(Pasteboard *)sender provideData:(const char *)type
{
    id retval = nil;
    NXStream *stream;
    NXTypedStream *ts;

    if((type == NXPostScriptPboardType) || (type == NXAsciiPboardType)){
		if(stream = [sender readTypeToStream:WoodPboardType]){
	    	if(ts = NXOpenTypedStream(stream, NX_READONLY)){
				retval = self;
				if(type == NXPostScriptPboardType)
		    		[self convert:ts to:type using:@selector(writePSToStream:usingTree:) toPasteboard:sender];
				else 
		    		[self convert:ts toAsciiPasteboard:sender];
				NXCloseTypedStream(ts);
	    	}
	    	NXCloseMemory(stream, NX_FREEBUFFER);
		}
    } else if(strcmp(type, WoodOOEApplicationInfoPboardType) == 0){
		retval = self;
		[sender writeType:WoodOOEApplicationInfoPboardType data:WoodName length:strlen(WoodName)];
	}
    return retval;
}

- retrieveData:sender
{
	id pboard = nil;
	NXStream *stream = NULL;
	NXTypedStream *typedStream = NULL;
	const char *ftype = NULL;
	  
	pboard = [Pasteboard newName:OOE_PASTEBOARD];
	if(pboard == nil){	
		NXLogError("ERROR: No '%s' pasteboard!", WoodPboardType);
		return nil;
	}
    ftype = [pboard findAvailableTypeFrom:&WoodPboardType num:1];
	if(ftype == NULL){
		NXLogError("ERROR: No '%s' type in pasteboard '%s'!", WoodPboardType, OOE_PASTEBOARD);
		return nil;
	}
 	stream = [pboard readTypeToStream:WoodPboardType];
	typedStream = NXOpenTypedStream(stream, NX_READONLY);
	if(typedStream)
		[self makeAddOOETree:NXReadObject(typedStream)];
    if(typedStream)
		NXCloseTypedStream(typedStream);
    if(stream)
		NXCloseMemory(stream, NX_FREEBUFFER);
	return self;
}

- declareOOEPasteboard:pboard
{
	const char *types[2];
	int k = 0;
	
	types[k++] = NXPostScriptPboardType;
	types[k++] = WoodPboardType;
	[pboard declareTypes:types num:k owner:NXApp];	
	return self;
}

- writeDataToPasteboard:pboard
{
	NXStream *stream;
	NXTypedStream *typedStream;
	
   	stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	typedStream = NXOpenTypedStream(stream, NX_WRITEONLY);
	[tree writeToPBStream:typedStream];
	NXSeek(stream, 0, NX_FROMSTART);
    [pboard writeType:WoodPboardType fromStream:stream];
    if(typedStream)
		NXCloseTypedStream(typedStream);
    if(stream)
		NXCloseMemory(stream, NX_FREEBUFFER);
	return self;
}

- writePostScriptToPasteboard:pboard
{
	NXStream *stream = NULL;
	
    stream = NXOpenMemory(NULL, 0, NX_READWRITE);
	[treeView writePSToStream:stream usingTree:tree];
	NXSeek(stream, 0, NX_FROMSTART);
    [pboard writeType:NXPostScriptPboardType fromStream:stream];
    if(stream)
		NXCloseMemory(stream, NX_FREEBUFFER);	
	return self;
}

- writeOOESourceApplicationToPasteboard:pboard
{
	[pboard writeType:WoodOOEApplicationInfoPboardType data:WoodName length:strlen(WoodName)];
	return self;
}

@end
